﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
using System.Xml;

namespace ALinq.Mapping
{
    ///<summary>
    /// Represents the mapping of a domain object type to the columns of a database table.
    ///</summary>
    public class TypeMapping : ModelMapping
    {
        private Type @type;
        private ModelMappingCollection<ColumnMapping, MemberInfo> columns;
        private ModelMappingCollection<AssociationMapping, MemberInfo> associations;
        private ModelMappingCollection<TypeMapping, Type> derivedTypes;

        /// <summary>
        /// Initializes a new instance of the ALinq.Mapping.TypeMapping class
        /// </summary>
        /// <param name="entityType">A domain object type.</param>
        public TypeMapping(Type entityType)
            : base( ModelMappingType.Type)
        {
            this.Type = entityType;
            this.columns = new ModelMappingCollection<ColumnMapping, MemberInfo>(this, o => o.Member);
            this.associations = new ModelMappingCollection<AssociationMapping, MemberInfo>(this, o => o.Member);
            this.derivedTypes = new ModelMappingCollection<TypeMapping, Type>(this, o => o.Type);
        }

        ///<summary>
        /// Get a column-mapping by the member of the domain object type.
        ///</summary>
        ///<param name="member">Member of the domain object type.</param>
        ///<returns>A column-mapping.</returns>
        public ColumnMapping GetColumn(MemberInfo member)
        {
            var columnMapping = this.columns.GetItem(member);
            return columnMapping;
        }

        ///<summary>
        /// Get a association-mapping by the member of the domain object type.
        ///</summary>
        ///<param name="member">Member of the domain object type.</param>
        ///<returns>A association-mapping.</returns>
        public AssociationMapping GetAssociation(MemberInfo member)
        {
            var associationMapping = this.associations.GetItem(member);
            return associationMapping;
        }

        /// <summary>
        /// Gets the domain object type.
        /// </summary>
        public Type Type
        {
            get { return this.@type; }
            private set
            {
                if (value == null)
                    throw Error.MemberValueCanNotNull("Type");

                @type = value;
                Name = value.FullName;
            }
        }

        /// <summary>
        /// Gets name the of domain object type.
        /// </summary>
        private string Name
        {
            get { return GetAttribute(() => Name); }
            set { SetAttribute(() => Name, value); }
        }

        /// <summary>
        /// Gets a value indicating whether this type defines an inheritance code.
        /// </summary>
        public string InheritanceCode
        {
            get { return GetAttribute(() => InheritanceCode); }
            set { this.SetAttribute(() => InheritanceCode, value); }
        }

        /// <summary>
        /// Gets a value indicating whether this type is used as the default of an inheritance hierarchy.
        /// </summary>
        public bool IsInheritanceDefault
        {
            get { return GetAttribute(() => IsInheritanceDefault); }
            set { SetAttribute(() => IsInheritanceDefault, value); }
        }

        /// <summary>
        /// Gets an enumeration of all the mapping columns.
        /// </summary>
        public ICollection<ColumnMapping> Columns
        {
            get { return columns; }
        }

        /// <summary>
        /// Gets an enumeration of all the associations.
        /// </summary>
        public ICollection<AssociationMapping> Associations
        {
            get { return associations; }
        }

        /// <summary>
        /// Gets an enumeration of the immediate derived types in an inheritance hierarchy.
        /// </summary>
        public ICollection<TypeMapping> DerivedTypes
        {
            get { return derivedTypes; }
        }

        /// <summary>
        /// Gets the base type-mapping in the inheritance hierarchy.
        /// </summary>
        public TypeMapping InheritanceBase
        {
            get
            {
                return Parent as TypeMapping;
            }
        }
    }

    ///<summary>
    /// Represents the mapping of a domain object type to the columns of a database table.
    ///</summary>
    /// <typeparam name="TEntity">
    /// A domain object type.
    /// </typeparam>
    public class TypeMapping<TEntity> : TypeMapping
    {
        /// <summary>
        /// Initializes a new instance of the ALinq.Mapping.TypeMapping class
        /// </summary>
        public TypeMapping()
            : base(typeof(TEntity))
        {
        }

    }


}